package com.easychat.service.impl;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javax.annotation.Resource;

import com.easychat.config.AppConfig;
import com.easychat.entity.constants.Constants;
import com.easychat.entity.dto.MessageSendDTO;
import com.easychat.entity.dto.SysSettingDto;
import com.easychat.entity.dto.TokenUserInfoDto;
import com.easychat.entity.enums.*;
import com.easychat.entity.po.ChatSessionUser;
import com.easychat.entity.po.UserContact;
import com.easychat.entity.po.UserInfoBeauty;
import com.easychat.entity.query.*;
import com.easychat.entity.vo.account.response.LoginRspVO;
import com.easychat.exception.BusinessException;
import com.easychat.mappers.ChatSessionUserMapper;
import com.easychat.mappers.UserContactMapper;
import com.easychat.mappers.UserInfoBeautyMapper;
import com.easychat.service.UserContactService;
import com.easychat.utils.CopyTools;
import com.easychat.utils.RedisUtil;
import com.easychat.websocket.MessageHandler;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.easychat.entity.po.UserInfo;
import com.easychat.entity.vo.PaginationResultVO;
import com.easychat.mappers.UserInfoMapper;
import com.easychat.service.UserInfoService;
import com.easychat.utils.StringTools;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;


/**
 * 用户信息 业务接口实现
 */
@Service("userInfoService")
public class UserInfoServiceImpl implements UserInfoService {

	@Resource
	private UserInfoMapper<UserInfo, UserInfoQuery> userInfoMapper;

	@Resource
	private UserInfoBeautyMapper<UserInfoBeauty, UserInfoBeautyQuery> userInfoBeautyMapper;

	@Resource
	private AppConfig appConfig;

	@Resource
	private RedisUtil redisUtil;

    @Resource
    private UserContactMapper userContactMapper;

    @Resource
    private UserContactService userContactService;

    @Resource
    private RedisTemplate redisTemplate;

	@Resource
	private ChatSessionUserMapper<ChatSessionUser, ChatSessionUserQuery> chatSessionUserMapper;

	@Resource
	private MessageHandler messageHandler;

	/**
	 * 根据条件查询列表
	 */
	@Override
	public List<UserInfo> findListByParam(UserInfoQuery param) {
		return this.userInfoMapper.selectList(param);
	}

	/**
	 * 根据条件查询列表
	 */
	@Override
	public Integer findCountByParam(UserInfoQuery param) {
		return this.userInfoMapper.selectCount(param);
	}

	/**
	 * 分页查询方法
	 */
	@Override
	public PaginationResultVO<UserInfo> findListByPage(UserInfoQuery param) {
		int count = this.findCountByParam(param);
		int pageSize = param.getPageSize() == null ? PageSize.SIZE15.getSize() : param.getPageSize();

		SimplePage page = new SimplePage(param.getPageNo(), count, pageSize);
		param.setSimplePage(page);
		List<UserInfo> list = this.findListByParam(param);
		PaginationResultVO<UserInfo> result = new PaginationResultVO(count, page.getPageSize(), page.getPageNo(), page.getPageTotal(), list);
		return result;
	}

	/**
	 * 新增
	 */
	@Override
	public Integer add(UserInfo bean) {
		return this.userInfoMapper.insert(bean);
	}

	/**
	 * 批量新增
	 */
	@Override
	public Integer addBatch(List<UserInfo> listBean) {
		if (listBean == null || listBean.isEmpty()) {
			return 0;
		}
		return this.userInfoMapper.insertBatch(listBean);
	}

	/**
	 * 批量新增或者修改
	 */
	@Override
	public Integer addOrUpdateBatch(List<UserInfo> listBean) {
		if (listBean == null || listBean.isEmpty()) {
			return 0;
		}
		return this.userInfoMapper.insertOrUpdateBatch(listBean);
	}

	/**
	 * 多条件更新
	 */
	@Override
	public Integer updateByParam(UserInfo bean, UserInfoQuery param) {
		StringTools.checkParam(param);
		return this.userInfoMapper.updateByParam(bean, param);
	}

	/**
	 * 多条件删除
	 */
	@Override
	public Integer deleteByParam(UserInfoQuery param) {
		StringTools.checkParam(param);
		return this.userInfoMapper.deleteByParam(param);
	}

	/**
	 * 根据UserId获取对象
	 */
	@Override
	public UserInfo getUserInfoByUserId(String userId) {
		return this.userInfoMapper.selectByUserId(userId);
	}

	/**
	 * 根据UserId修改
	 */
	@Override
	public Integer updateUserInfoByUserId(UserInfo bean, String userId) {
		return this.userInfoMapper.updateByUserId(bean, userId);
	}

	/**
	 * 根据UserId删除
	 */
	@Override
	public Integer deleteUserInfoByUserId(String userId) {
		return this.userInfoMapper.deleteByUserId(userId);
	}

	/**
	 * 根据Email获取对象
	 */
	@Override
	public UserInfo getUserInfoByEmail(String email) {
		return this.userInfoMapper.selectByEmail(email);
	}

	/**
	 * 根据Email修改
	 */
	@Override
	public Integer updateUserInfoByEmail(UserInfo bean, String email) {
		return this.userInfoMapper.updateByEmail(bean, email);
	}

	/**
	 * 根据Email删除
	 */
	@Override
	public Integer deleteUserInfoByEmail(String email) {
		return this.userInfoMapper.deleteByEmail(email);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void register(String nickName, String password, String email) {
		// 先查邮箱是否存在
		UserInfo userInfo = userInfoMapper.selectByEmail(email);
		if (null != userInfo) {
			throw new BusinessException("邮箱已存在");
		}
		UserInfoBeauty userInfoBeauty = this.userInfoBeautyMapper.selectByEmail(email);
		String userId = StringTools.getUserId();
		// 查找是否靓号
		Boolean useBeautyAccount = null != userInfoBeauty && userInfoBeauty.getStatus().equals(BeautyAccountStatusEnum.NO_USE.getStatus());
		if (useBeautyAccount) {
			// 未使用情况下
			userId = UserContactTypeEnum.USER.getPrefix() + userInfoBeauty.getUserId();
		}
		Date currentDate = new Date();
		userInfo = UserInfo.builder()
				.userId(userId)
				.nickName(nickName)
				.email(email)
				.password(StringTools.encodeMD5(password))
				.createTime(currentDate)
				.status(UserStatusEnum.ENABLE.getCode())
				.lastLoginTime(currentDate)
				.lastOffTime(currentDate.getTime())
				.joinType(1)
				.build();
		userInfoMapper.insert(userInfo);

		if (useBeautyAccount) {
			// 已使用情况下, 更新靓号状态
			UserInfoBeauty userInfoBeautyAccount = UserInfoBeauty.builder()
					.status(BeautyAccountStatusEnum.USED.getStatus())
					.build();
			userInfoBeautyMapper.updateByUserId(userInfoBeautyAccount, userInfoBeauty.getUserId());
		}
		userContactService.addContactRobot(userId);
	}

	@Override
	public LoginRspVO login(String email, String password) {
		// 登录：根据邮箱查询用户信息，校验密码
		UserInfo dbUserInfo = userInfoMapper.selectByEmail(email);
		if (null == dbUserInfo || !password.equals(dbUserInfo.getPassword())) {
			throw new BusinessException("账号或密码不正确");
		}
		if (dbUserInfo.getStatus().equals(UserStatusEnum.DISABLE.getCode())) {
			throw new BusinessException("用户已被禁用");
		}

		TokenUserInfoDto tokenUserInfoDto = getTokenUserInfoDto(dbUserInfo);
		// 判断心跳是否存在，如果存在，则说明已经登录了
		Long lastUserHeartBeat = redisUtil.getUserHeartBeat(dbUserInfo.getUserId());
		if (null != lastUserHeartBeat) {
			throw new BusinessException("此账号已在别处登录，请退出后再登录");
		}
		UserContactQuery userContactQuery = new UserContactQuery();
		userContactQuery.setUserId(dbUserInfo.getUserId());
		userContactQuery.setStatus(UserContactStatusEnum.FRIEND.getStatus());
		List<UserContact> userContactList = userContactService.findListByParam(userContactQuery);
		List<String> userContactIdList = userContactList.stream().map(i -> i.getContactId()).collect(Collectors.toList());

		redisUtil.del(Constants.REDIS_KEY_USER_CONTACT + dbUserInfo.getUserId());
		// 批量添加联系人，在添加时先清空
		if (!userContactList.isEmpty()) {
			userContactIdList.forEach(i -> redisTemplate.opsForList().rightPush(Constants.REDIS_KEY_USER_CONTACT + dbUserInfo.getUserId(), i));
			redisTemplate.expire(Constants.REDIS_KEY_USER_CONTACT + dbUserInfo.getUserId(), Constants.REDIS_KEY_EXPIRE_DAY * 2, TimeUnit.SECONDS);
		}

		// 生成token
		String token = StringTools.encodeMD5(dbUserInfo.getUserId() + Constants.RANDOM_CODE_LENGTH);
		tokenUserInfoDto.setToken(token);

		// 存放到Redis中
		redisUtil.set(Constants.REDIS_KEY_WS_TOKEN + tokenUserInfoDto.getToken(), tokenUserInfoDto, Constants.REDIS_KEY_EXPIRE_DAY * 2);
		redisUtil.set(Constants.REDIS_KEY_WS_TOKEN_USERID + tokenUserInfoDto.getToken(), tokenUserInfoDto.getToken(), Constants.REDIS_KEY_EXPIRE_DAY * 2);

		LoginRspVO loginRspVO = CopyTools.copy(dbUserInfo, LoginRspVO.class);
		loginRspVO.setAdmin(tokenUserInfoDto.getAdmin());
		loginRspVO.setToken(tokenUserInfoDto.getToken());
		// 存放系统配置
		redisUtil.set(Constants.REDIS_KEY_SYS_SETTING, new SysSettingDto(), Constants.REDIS_KEY_EXPIRE_DAY * 2);

		return loginRspVO;
	}

	private TokenUserInfoDto getTokenUserInfoDto(UserInfo userInfo) {
		TokenUserInfoDto tokenUserInfoDto = TokenUserInfoDto.builder()
				.userId(userInfo.getUserId())
				.nickName(userInfo.getNickName())
				.admin(false)
				.build();

		String adminEmail = appConfig.getAdminEmail();

		if (!StringTools.isEmpty(adminEmail) && ArrayUtils.contains(adminEmail.split(","), userInfo.getEmail())) {
			tokenUserInfoDto.setAdmin(true);
		}
		return tokenUserInfoDto;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateUserInfo(UserInfo userInfo, MultipartFile avatarFile, MultipartFile avatarCover) {
		if (null != avatarFile) {
			String baseFolder = appConfig.getProjectFolder() + Constants.FILE_FOLDER_FILE;
			File targetFileFolder = new File(baseFolder + Constants.FILE_FOLDER_AVATAR_NAME);
			if (!targetFileFolder.exists()) {
				targetFileFolder.mkdirs();
			}
			String filePath = targetFileFolder.getPath() + "/" + userInfo.getUserId() + Constants.IMAGE_SUFFIX;
            try {
                avatarFile.transferTo(new File(filePath));
				avatarCover.transferTo(new File(filePath + Constants.COVER_IMAGE_SUFFIX));
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
		UserInfo dbUserInfo = userInfoMapper.selectByUserId(userInfo.getUserId());
		userInfoMapper.updateByUserId(userInfo, userInfo.getUserId());
		String nickNameUpdate = null;
		if (!dbUserInfo.getNickName().equals(userInfo.getNickName())) {
			nickNameUpdate = userInfo.getNickName();
		}
		if (null == nickNameUpdate) {
			return;
		}
		this.chatSessionUserMapper.updateContactName(dbUserInfo.getUserId(), nickNameUpdate);

		UserContactQuery userContactQuery = new UserContactQuery();
		userContactQuery.setContactType(UserContactTypeEnum.USER.getType());
		userContactQuery.setContactId(userInfo.getUserId());
		userContactQuery.setStatus(UserContactStatusEnum.FRIEND.getStatus());
		List<UserContact> userContactList = userContactMapper.selectList(userContactQuery);

		for (UserContact userContact : userContactList) {
			MessageSendDTO messageSendDTO = new MessageSendDTO();
			messageSendDTO.setContactType(UserContactTypeEnum.USER.getType());
			messageSendDTO.setContactId(userContact.getUserId());
			messageSendDTO.setExtendData(nickNameUpdate);
			messageSendDTO.setSendUserId(userInfo.getUserId());
			messageSendDTO.setSendUserNickName(userInfo.getNickName());
			messageSendDTO.setMessageType(MessageTypeEnum.CONTACT_NAME_UPDATE.getType());
			messageHandler.sendMessage(messageSendDTO);
		}
		// 更新token中的昵称
		String token = (String) redisUtil.get(Constants.REDIS_KEY_WS_TOKEN_USERID + userInfo.getUserId());
		TokenUserInfoDto tokenUserInfoDto = redisUtil.getTokenUserInfoDto(token);
		tokenUserInfoDto.setNickName(nickNameUpdate);
		redisUtil.saveTokenUserInfoDto(tokenUserInfoDto);

	}

	@Override
	public void forceOffLine(String userId) {
		MessageSendDTO messageSendDTO = new MessageSendDTO();
		messageSendDTO.setContactId(userId);
		messageSendDTO.setContactType(UserContactTypeEnum.USER.getType());
		messageSendDTO.setMessageType(MessageTypeEnum.FORCE_OFF_LINE.getType());
		messageHandler.sendMessage(messageSendDTO);
	}
}